package erwiki.ui.app.parts.navigation;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.menu.MToolItem;
import org.eclipse.e4.ui.services.EMenuService;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.elwiki_data.WikiPage;

import erwiki.api.core.Engine;
import erwiki.api.exceptions.ProviderException;
import erwiki.api.pages.PageManager;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;
import jakarta.inject.Named;

public class NavigationView {

	public static final String ID = "erwiki.ui.part.wikiexplorer";

	private ComposedAdapterFactory composedAdapterFactory;

	private TreeViewer treeViewer;

	protected WikiPage selectedWikiPage;

	@Deprecated
	private Action createPageAction;

	@Deprecated
	private Action renamePageAction;

	@Deprecated
	private Action removePageAction;

	@Inject
	ESelectionService selectionService;

	@Inject
	Engine engine;

	private boolean isSyncingSelection;

	private WikiPage currentPage;

	// == CODE ================================================================

	/**
	 * Create contents of the view part.
	 *
	 * @param composite
	 * @wbp.parser.entryPoint
	 */
	@PostConstruct
	public void createPartControl(Composite parent, EMenuService menuService) {
		Composite composite = new Composite(parent, SWT.NONE);
		// Create a grid layout object so the text and treeviewer are layed out the way I want.
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.verticalSpacing = 2;
		layout.marginWidth = 0;
		layout.marginHeight = 2;
		composite.setLayout(layout);

		this.treeViewer = new TreeViewer(composite);
		this.treeViewer.setUseHashlookup(true);

		// layout the tree viewer below the text field
		GridData layoutData = new GridData();
		layoutData.grabExcessHorizontalSpace = true;
		layoutData.grabExcessVerticalSpace = true;
		layoutData.horizontalAlignment = GridData.FILL;
		layoutData.verticalAlignment = GridData.FILL;
		this.treeViewer.getControl().setLayoutData(layoutData);

		this.treeViewer.setSorter(new ViewerSorter() {
			private static final long serialVersionUID = 7091254015719263756L;

			@Override
			public int compare(Viewer viewer1, Object e1, Object e2) {
				if (e1 instanceof WikiPage && e2 instanceof WikiPage) {
					String s1 = ((WikiPage) e1).getName();
					String s2 = ((WikiPage) e2).getName();
					return s1.compareTo(s2);
				}
				return super.compare(viewer1, e1, e2);
			}
		});

		Tree tree = treeViewer.getTree();
		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		// --------------------------------------------------------------------
		// :FVK:

		// register context menu on the treeViewer.
		menuService.registerContextMenu(treeViewer.getControl(), "erwiki.ui.popupmenu.treeviewer.navigate");

		// передача выбранной страницы в ESelectionService E4.
		treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				IStructuredSelection selection = event.getStructuredSelection();
				selectionService.setSelection(selection.getFirstElement());

				// TODO: Pop-up меню для изменения данных доступно только пользователям соответствующей роли.
				NavigationView.this.selectedWikiPage = (selection.isEmpty()) ? null
						: (WikiPage) selection.getFirstElement();
			}
		});

		this.treeViewer.setContentProvider(new NavContentProvider()); // ----:FVK:
		this.treeViewer.setLabelProvider(new NavLabelProvider());

		// PagesStore pages = IModel.INSTANCE.getPagesStore(); // workaround.
		// ----:FVK:

		// PagesStore pages = AppUiActivator.getDefault().getAppSession().getStorageCdo().getPagesStore();
		// // workaround.
		PageManager pageManager = engine.getManager(PageManager.class);
		String mainPageId = pageManager.getMainPageId();
		WikiPage mainPage = null;
		try {
			mainPage = pageManager.getPageById(mainPageId);
		} catch (ProviderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		WikiPage[] wikiPages = (mainPage != null) ? new WikiPage[] { mainPage } : new WikiPage[0];
		this.treeViewer.setInput(wikiPages);

		this.treeViewer.expandToLevel(2);

		/* ----:FVK:
		getSite().setSelectionProvider(this.treeViewer);
		ISelectionService s = getSite().getWorkbenchWindow().getSelectionService();
		s.addSelectionListener(this.mylistener);
		 */

		// --------------------------------------------------------------------

		/* ----:FVK:
		createActions();
		initializeToolBar();
		initializeMenu();
		 */
	}

	public WikiPage getSelectedWikiPage() {
		if (this.selectedWikiPage != null) {
			return this.selectedWikiPage;
		}
		return null;
	}

	/*
	private IPropertySheetPage getPropertySheetPage() {
		PropertySheetPage propertySheetPage = new PropertySheetPage();
		propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(getAdapterFactory()));
	
		return propertySheetPage;
	}
	 */

	@Focus
	public void focus() {

	}
	/*
	private ISelectionListener mylistener = new ISelectionListener() {
		public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
			if (sourcepart != NavigationView.this && selection instanceof IStructuredSelection) {
				if (!selection.isEmpty()) {
					NavigationView.this.treeViewer.setSelection(selection, true);
				}
			}
		}
	};
	
	@Override
	public Object getAdapter(@SuppressWarnings("rawtypes") Class key) {
		/ * TODO: feature request.
	 * if (IContentOutlinePage.class.equals(key)) {
			return showOutlineView() ? getContentOutlinePage() : null;
		} else* /
		if (IPropertySheetPage.class.equals(key)) {
			return getPropertySheetPage();
		}
		return super.getAdapter(key);
	}

	private IPropertySheetPage getPropertySheetPage() {
		PropertySheetPage propertySheetPage = new PropertySheetPage();
		propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(getAdapterFactory()));

		return propertySheetPage;
	}
	 */

	/**
	 * Устанавливает флаг синхронизации выбора активной страниц Wiki: Browser -> Navigator.
	 *
	 * @param isSyncingSelection
	 */
	public void setSyncingSelection(boolean isSyncingSelection) {
		this.isSyncingSelection = isSyncingSelection;
		if (isSyncingSelection == true) {
			if (currentPage != null) {
				treeViewer.setSelection(new StructuredSelection(currentPage), true);
			}
		}
	}

	@Inject
	public void reactOnSelection(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) WikiPage wikiPage,
			@Named(IServiceConstants.ACTIVE_PART) MPart activePart) {
		// Игнорировать свой вызов - избежать рекурсивной передачи выбранной страницы.
		if (wikiPage == null || activePart == null || this.getClass() == activePart.getObject().getClass()) {
			return;
		}
		this.currentPage = wikiPage;
		if (isSyncingSelection) {
			treeViewer.setSelection(new StructuredSelection(wikiPage), true);
		}
	}

}

/**
 * Реагирует на изменение состояния кнопки переключения синхронизации выбора текущей страницы.
 */
class ActionSyncingButton {
	@Execute
	public void execute(MToolItem item, @Named(IServiceConstants.ACTIVE_PART) MPart mPart) {
		if (mPart.getObject() instanceof NavigationView navigationView) {
			navigationView.setSyncingSelection(item.isSelected());
		}
	}
}
